package com.gbas.mus;

import com.gbas.model.Mazo;
import com.gbas.model.Naipe;
import com.gbas.model.VALOR;
import com.gbas.mus.model.*;
import com.gbas.mus.model.lances.Lance;

import java.util.*;

public class JugarMus {
    ModoMus modoMus;
    Jugadores jugadores;
    Partida partida = null;

    public ModoMus getModoMus() {
        return modoMus;
    }

    public void setModoMus(ModoMus modoMus) {
        this.modoMus = modoMus;
    }

    public Jugadores getJugadores() {
        return jugadores;
    }

    public void setJugadores(Jugadores jugadores) {
        this.jugadores = jugadores;
    }

    public void jugar() {
        partida = new Partida(this, jugadores, modoMus);
        partida.jugar();
    }

    public void recibeInput(Lance lance) {
        partida.vacaActual.juegoActual.rondaActual.faseActual.addLance(lance);
    }


    static List<Set<VALOR>> ordenVictoria = new ArrayList<Set<VALOR>>();

    final VALOR[] gananGrandes = {VALOR.CABALLO, VALOR.SOTA, VALOR.SIETE, VALOR.SEIS, VALOR.CINCO, VALOR.CUATRO};
    final VALOR[] gananChicas = {VALOR.CUATRO, VALOR.CINCO, VALOR.SEIS, VALOR.SIETE, VALOR.SOTA, VALOR.CABALLO};
    final VALOR[] parDescendente = {VALOR.REY, VALOR.CABALLO, VALOR.SOTA, VALOR.SIETE, VALOR.SEIS, VALOR.CINCO, VALOR.CUATRO, VALOR.AS};

    public boolean naipesAspiranteGanan(Class tipoVictoria, Naipe[] ganador, Naipe[] aspirante) {
        if (tipoVictoria == FaseGrandes.class) {
            int cerdosGanador = cuentaCartasConValor(ganador, VALOR.REY) + cuentaCartasConValor(ganador, VALOR.TRES);
            int cerdosAspirante = cuentaCartasConValor(aspirante, VALOR.REY) + cuentaCartasConValor(aspirante, VALOR.TRES);

            if (cerdosGanador > cerdosAspirante) {
                return false;
            } else if (cerdosAspirante > cerdosGanador) {
                return true;
            } else {
                for (VALOR v : gananGrandes) {
                    cerdosGanador = cuentaCartasConValor(ganador, v);
                    cerdosAspirante = cuentaCartasConValor(aspirante, v);

                    if (cerdosGanador > cerdosAspirante) {
                        return false;
                    } else if (cerdosAspirante > cerdosGanador) {
                        return true;
                    }
                }
                return false;
            }
        } else if (tipoVictoria == FaseChicas.class) {
            // Chica
            int chicaGanador = cuentaCartasConValor(ganador, VALOR.AS) + cuentaCartasConValor(ganador, VALOR.DOS);
            int chicaAspirante = cuentaCartasConValor(aspirante, VALOR.AS) + cuentaCartasConValor(aspirante, VALOR.DOS);

            if (chicaGanador > chicaAspirante) {
                return false;
            } else if (chicaAspirante > chicaGanador) {
                return true;
            } else {
                for (VALOR v : gananChicas) {
                    chicaGanador = cuentaCartasConValor(ganador, v);
                    chicaAspirante = cuentaCartasConValor(aspirante, v);

                    if (chicaGanador > chicaAspirante) {
                        return false;
                    } else if (chicaAspirante > chicaGanador) {
                        return true;
                    }
                }
                return false;
            }
        } else if (tipoVictoria == FasePar.class) {
            int parGanador = Fase.getValorPares(ganador);
            int parAspirante = Fase.getValorPares(aspirante);

            if (parGanador > parAspirante) {
                return false;
            } else if (parAspirante > parGanador) {
                return true;
            } else if (parGanador > 0) {
                Map<VALOR, Integer> paresGanador = Fase.getMapaPares(ganador);
                Fase.removeWithoutPar(paresGanador);
                Map<VALOR, Integer> paresAspirante = Fase.getMapaPares(aspirante);
                Fase.removeWithoutPar(paresAspirante);

                for (VALOR v : parDescendente) {
                    if (paresGanador.get(v) != null && paresAspirante.get(v) == null) {
                        return false;
                    } else if (paresAspirante.get(v) != null && paresGanador.get(v) == null) {
                        return true;
                    }
                }

                return false;

            } else {
                return false;
            }

        } else if (tipoVictoria == FaseJuego.class) {
            int puntosGanador = Fase.cuentaPuntos(ganador);
            int puntosAspirante = Fase.cuentaPuntos(aspirante);

            return puntosGanador != 31 && (puntosAspirante == 31 || puntosGanador < puntosAspirante);
        }
        return false;
    }


    public int cuentaCartasConValor(Naipe[] naipes, VALOR v) {
        int cuenta = 0;

        for (Naipe n : naipes) {
            if (n.getValor() == v) {
                cuenta++;
            }
        }
        return cuenta;
    }

    public int equipoGanador(int jugadorMano, Class tipoVictoria) {
        JugadorMus ganador = jugadores.getJugador(jugadorMano);
        JugadorMus otro = ganador;
        for (int k = 0; k < 3; k++) {
            otro = jugadores.getNextJugador(otro);
            if (naipesAspiranteGanan(tipoVictoria, ganador.getNaipes(), otro.getNaipes())) {
                ganador = otro;
            }
        }
        return ganador.getEquipo();
    }


    public void accionMesa(Accion accion, Object helper) {
        accionMesa(accion, helper, null);
    }

    public void accionMesa(Accion accion, Object helper, Object helper2) {
        // TODO
        switch (accion) {
            case REPARTE_CARTAS:
                accionReparteCartasInicial((Integer) helper);
                break;
            case CAMBIA_CARTAS:
                accionEnviaCartasDescarte((JugadorMus) helper, (Set<Naipe>) helper2);
                break;
            case MUESTRA_FINRONDA:
                break;
            case RECOGE_CARTAS:
                break;
            case MENSAJE_TEXTO:
                accionEnviaMensajeATodos((String) helper);
                break;
            case CANCELA_ENTRADA:
                accionCancelaEntradaJugador((JugadorMus) helper);
                break;
        }

    }

    private void accionReparteCartasInicial(int jugadorMano) {
        partida.mazoCartas = new Mazo();
        partida.mazoCartas.mezcla();

        JugadorMus jMus = jugadores.getJugador(jugadorMano);
        for (int k = 0; k < 16; k++) {
            jMus.setNaipe(k / 4, partida.mazoCartas.getNaipe());
            jMus = jugadores.getNextJugador(jMus);
        }

        for (int k = 0; k < 4; k++) {
            jMus.takeYourCards();
            jMus = jugadores.getNextJugador(jMus);
        }
    }

    private void accionCancelaEntradaJugador(JugadorMus jugador) {
        jugador.cancelaEntrada();
    }

    private void accionEnviaCartasDescarte(JugadorMus jugador, Set<Naipe> cartasDescartadas) {
        partida.mazoCartas.addNaipes(cartasDescartadas);
        Set<Naipe> nuevasCartas = new HashSet<Naipe>();
        int pos = 0;
        for (Naipe n : jugador.getNaipes()) {
            if (cartasDescartadas.contains(n)) {
                Naipe nueva = partida.mazoCartas.getNaipe();
                nuevasCartas.add(nueva);
                jugador.setNaipe(pos, nueva);
            }
            pos++;
        }

        jugador.takeThisCards(nuevasCartas);
    }


    private void accionEnviaMensajeATodos(String msg) {
        // TODO
        JugadorMus jMus = jugadores.getJugador(0);
        for (int k = 0; k < 4; k++) {
            jMus.sendTexto(msg);
            jMus = jugadores.getNextJugador(jMus);
        }

    }

    public Partida getPartida() {
        return partida;
    }
}

